Astro と CSS Modules を使用した React のコンポーネントの、開発と本番時における style の優先順の差異
すこし前の話になるのですが、SSG している自分のブログをNext.jsからAstroに置き換えました。置き換えた経緯などはそちらで記事にしています。そのためここでは、Astro コンポーネントのスタイルについての詳細には言及していません。
今回発生した現象修正した PR としては以下になります。
経緯
自分のブログを時間があるときに少しずつ機能実装しているのですが、あるとき本番環境でスタイルが崩れていることに気づきました。
結構目立つスタイルの崩れだったので、なぜ開発中に気づかなかったのか疑問に思いながら開発環境を立ち上げると、現象の再現はしませんでした。
本番環境 | 開発環境 |
---|---|
調査
CSS なので調査は難しくありません、Devtools で確認してみます。
本番環境 | 開発環境 |
---|---|
本番環境では次のようになっています。
index.6061e360.css
ファイルが生成されていて、どちらも同じファイル内で記述されているdisplay: block;
が指定されている._root_r8td5_1
はファイル内で後に記述され優先されているdisplay: flex;
が指定されている.menu:where(.astro-YPTKBFHU) > *
はファイル内で先に記述され上書きされている
開発環境では次のようになっています。
display: flex;
が指定されている._root_r8td5_1
はstyles.module.css
ファイルに記述され、上書きされているdisplay: block;
が指定されている.menu:where(.astro-YPTKBFHU) > *
はstyle
要素に記述され、優先されている
詳細度は同じである
._root_r8td5_1
と .menu:where(.astro-YPTKBFHU) > *
の詳細度はともに 0,1,0 となっています。一見 .menu:where(.astro-YPTKBFHU) > *
の詳細度が高いように思えますが、全称セレクタは重みの計算にカウントされません。
詳細度を細かく数値として Devtools で確認することができないので、計算ツールを用いることが多いです。ただし検索するとでてくるツールで、まれに :where()
に未対応のものがあったりするので注意が必要です。ここでは Polypane の CSS Specificity Calculator をオススメしておきます。
次に優先されるもの
CSS の優先順位については以前書いた詳細度よりも優先される CSS の Cascade Layers についてという記事で解説しています。
開発環境ではその origin の違いから style
要素に記述されている CSS が適用され、本番環境では同一ファイル内での出現順序の違いにより、後に記述されている CSS が適用されているという現象が発生していることが確認できました(ビルド結果での出現順位は常に固定というわけではなさそう)。
結論
Astro のコンポーネントでは、:where()
疑似クラスを使用したカプセル化を行うため、詳細度が高くなりません。そのため CSS Modules を使っている React のコンポーネントと合わせて使用する場合、開発環境と本番環境でその優先順位に差異が発生するケースがありそうです。
今回のケースでは全称セレクタを、具体的な要素名に変更する対応をとることで一時的な解決は可能です。しかしそれは根本的な解決策ではなく、Astro コンポーネントから React のコンポーネントへの CSS の干渉を避けるべきであるように感じました。